import http from "@/utils/http";
import Vue from "vue";
import VueCookie from "vue-cookie";
import Router from "vue-router";
import VueStore from "@/store";
import { clearLoginInfo } from "@/utils/auth";

const originalPush = Router.prototype.push;
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err && console.debug(err));
};
Vue.use(Router);

// 通用路由
const globalRoutes = [
  {
    path: "/404",
    component: () => import("@/views/404"),
    name: "404",
    meta: { title: "404 NOT FOUND" },
  },
  {
    path: "/login",
    component: () => import("@/views/login"),
    name: "login",
    meta: { title: "Login" },
  },
];

// 主路由
const mainRoutes = {
  path: "/",
  exact: true,
  component: () => import("@/layout/default"),
  name: "main",
  redirect: { name: "home" },
  meta: { title: "主入口整体布局" },
  children: [
    {
      path: "home",
      component: () => import("@/views/home"),
      name: "home",
      meta: { title: "Dashboard" },
    },
  ],
};

mainRoutes.beforeEnter = (to, from, next) => {
  let token = VueCookie.get("token");
  if (!token || !/\S/.test(token)) {
    clearLoginInfo();
    next({ name: "login" });
  }
  next();
};

// 路由对象
const createRouter = () =>
  new Router({
    mode: process.env.NODE_ENV === "development" ? "hash" : "history",
    scrollBehavior(to, from, savedPosition) {
      if (savedPosition) {
        return savedPosition;
      } else {
        return { x: 0, y: 0 };
      }
    },
    isFill: false,
    routes: [...globalRoutes, mainRoutes],
  });

const router = createRouter();

export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher;
}

router.beforeEach(async (to, from, next) => {
  if (to.meta.title) {
    document.title = "Company Management-" + to.meta.title;
  }
  if (router.options.isFill || globalRoutes.find(i => i.path === to.path)) {
    next();
  } else {
    // 之前未填充主路由，并且不是 404 等全局路由的情况，需要填充主路由。
    resetRouter();
    await fillMainRoutes();
    next({ ...to, replace: true });
  }
});

// 填补菜单路由
const fillMainRoutes = async () => {
  const {
    code,
    data: { menuList, roleAuthorities },
  } = await http.get("/sysMenu/nav");
  if (code === 200) {
    VueStore.dispatch("authority/initAuthorities", roleAuthorities);

    let routeObj = {
      defaultRoutes: { ...mainRoutes },
    };

    const items = flatAll(menuList);
    items.forEach(item => {
      if (item.url) {
        const _component = _import(`${item.url}`);
        if (_component) {
          //默认布局
          if (!_component.layout || _component.layout === "default") {
            routeObj.defaultRoutes.children.push({
              path: item.url,
              exact: true,
              component: _component || null,
              name: item.url,
              meta: {
                menuId: item.menuId,
                title: item.name,
                isDynamic: true,
                isTab: false,
                ..._component?.meta,
              },
            });
          } else {
            const _layout = _component.layout;
            if (!routeObj[_layout]) {
              routeObj[_layout] = {
                path: "/",
                exact: true,
                component: () => import("@/layout/" + _layout),
                name: _layout,
                redirect: { name: "home" },
                children: [],
              };
            }
            routeObj[_layout].children.push({
              path: item.url,
              exact: true,
              component: _component || null,
              name: item.url,
              meta: {
                menuId: item.menuId,
                title: item.name,
                isDynamic: true,
                isTab: false,
                ..._component?.meta,
              },
            });
          }
        }
      }
    });

    const routeList = [...Object.values(routeObj), { path: "*", redirect: { name: "404" } }];
    routeList.forEach(route => {
      router.addRoute(route);
    });
    //副作用
    router.options.isFill = true;
    sessionStorage.setItem("dynamicMenuRoutes", JSON.stringify(routeObj.defaultRoutes.children || "[]"));
  }
};

//懒加载引入路由。 开发环境不使用懒加载, 因为懒加载页面太多的话会造成webpack热更新太慢, 所以只有生产环境使用懒加载
// const _import = require("./import-" + process.env.NODE_ENV);
// `约定式路由`需要从组件中获取元信息，故禁用懒加载 (2021.02.22 by lg)
const _import = require("./import-development");

// 将树型元素转成扁平元素
function flatAll(list) {
  function flat(x, z = []) {
    z.push(x);
    if (x.children) {
      x.children.forEach(child => flat(child, z));
    }
    return z;
  }
  return list.flatMap(i => flat(i));
}

// 重新填充路由（如菜单发生变化）
export function refillRoutes() {
  return new Promise((resolve, reject) => {
    resetRouter();
    fillMainRoutes()
      .then(function () {
        resolve();
      })
      .catch(function () {
        reject(new Error("fail get main routes"));
      });
  });
}

export default router;
